﻿using System;
using System.Collections.Generic;
using Ninject;
using Ninject.Parameters;

namespace Calculator
{
    public class InfixExpression : MathExpression
    {
        private readonly IExpressionValidator expressionValidator;

        private readonly NinjectContainer ninjectContainer;

        public InfixExpression(string expressionParam, ISymbolHandler symbolHandlerParam, IExpressionValidator expressionValidatorParam, IOperatorHandler operatorHandlerParam)
            : base(expressionParam, symbolHandlerParam, operatorHandlerParam)
        {
            expressionValidator = expressionValidatorParam;

            if (expressionValidator.Validate(expressionParam) == false)
                throw new ArgumentException("Выражение введено некорректно");

            Expression = expressionParam;

            ninjectContainer = new NinjectContainer();
        }

        public PostfixExpression ReturnPostfixExpression()
        {
            var resultString = "";
            var operatorStack = new Stack<char>();

            IfFirstIsOperationThenInsertZero();

            foreach (string piece in SplitExpressionIntoPieces())
            {
                resultString = symbolHandler.SymbolHandle(operatorStack, resultString, piece);
            }

            resultString = symbolHandler.PopWholeStackToResult(resultString, operatorStack);

            return ninjectContainer.NinjectKernel.Get<PostfixExpression>(new ConstructorArgument("expressionParam", resultString));
        }

        private void IfFirstIsOperationThenInsertZero()
        {
            if (operatorHandler.IsOperator(Expression[0]))
            {
                Expression = "0" + Expression;
            }
        }

        private IEnumerable<string> SplitExpressionIntoPieces()
        {
            var result = new List<string>();
            int i = 0;
            while (i < Expression.Length)
            {
                if (operatorHandler.IsOperator(Expression[i]) || Expression[i] == '(' || Expression[i] == ')')
                {
                    result.Add(Expression[i].ToString());
                }
                else if (operatorHandler.IsNumber(Expression[i]))
                {
                    string number = "";
                    while (i < Expression.Length && operatorHandler.IsNumber(Expression[i]))
                    {
                        number += Expression[i];
                        i++;
                    }
                    i--;
                    result.Add(number);
                }
                i++;
            }

            return result;
        }
    }
}